/**
 * Copyright (c) 2008 Luciano Bustos - riaevolution.com, All Rights Reserved.
 *
 * Contact luchyx@riaevolution.com
 * See www.riaevolution.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * */
package com.riaevolution.components.ToolTipGuide
{
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	import mx.containers.Canvas;
	import mx.controls.Text;
	import mx.controls.TextArea;
	import mx.controls.ToolTip;
	import mx.core.Container;
	import mx.core.IFlexDisplayObject;
	import mx.core.UIComponent;
	import mx.effects.Fade;
	import mx.effects.WipeLeft;
	import mx.events.CloseEvent;
	import mx.events.MoveEvent;
	import mx.events.ResizeEvent;
	import mx.managers.PopUpManager;
	import mx.styles.CSSStyleDeclaration;
	import mx.styles.StyleManager;

	[Style(name="icon", type="Class", inherit="no")]
	[Event(name="close")]

	/**
	 * ToolTipGuide is a helpfull tooltip displayed at start-up to ensure the user get the main concept of that portion of user interface.
	 *
	 * <b>author</b> Luciano Bustos
	 */
	public class ToolTipGuideWindow extends Container
	{
		protected var textArea:Text;
		protected var crossIcon:UIComponent;

		private var _htmlText:String;
		private var _htmlTextChanged:Boolean=false;

		private var _arrowPosition:String=ToolTipGuidePosition.BOTTOM_OUT;
		private var _arrowPositionChanged:Boolean=false;

		/**
		 * hold an icon instace
		 */
		protected var iconInst:UIComponent;

		public function ToolTipGuideWindow()
		{
			super();
		}

		[Embed(source="icon_bulb-grey.png")]
		private static const defaultIcon:Class;
		/**
		 * Initialize default styles
		 */
		private static var classConstructed:Boolean=classConstruct();

		/**
		 * Initialize default styles
		 * Styles initialization
		 */
		private static function classConstruct():Boolean
		{
			// Check if a CSSStyleDeclaration exists for the component
			var style:CSSStyleDeclaration=StyleManager.getStyleDeclaration("ToolTipGuideWindow");
			if (!style)
			{
				// If not, create a new one
				style=new CSSStyleDeclaration();
				// and set style default values using an inline function
				style.defaultFactory=function():void
				{
					// Template:
					// this.<myStyle> = <styleDefaultValue>;
					this.borderSkin=ToolTipGuideWindowBackground;
					this.backgroundColor=0xFBC12F;
					this.borderStyle="solid";
					this.dropShadowEnabled=true;
					this.icon=defaultIcon;
				};

				// Assign the style declaration
				StyleManager.setStyleDeclaration("ToolTipGuideWindow", style, true);
			}
			else
			{
				// Ensure that default values exist for all our style properties
				if (style.getStyle("borderSkin") == null)
				{
					style.setStyle("borderSkin", ToolTipGuideWindowBackground);
				}
				if (style.getStyle("icon") == undefined)
				{
					style.setStyle("icon", defaultIcon);
				}
				if (style.getStyle("borderStyle") == undefined)
				{
					style.setStyle("borderStyle", "solid");
				}
				if (style.getStyle("backgroundColor") == undefined)
				{
					style.setStyle("backgroundColor", 0xFBC12F);
				}
				if (style.getStyle("dropShadowEnabled") == undefined)
				{
					style.setStyle("dropShadowEnabled", true);
				}
			}
			return true;
		}
		/**
		 * Flag to ignore the automatic display of tooltips windows.<br />
		 * This is helpfull if you has to avoid null pointer or add more logic if this tooltips are disabled.<br />
		 * If <b>enabled = false</b> the method <i>show</i> will return the instance as spected but wont add the tooltip into the display list.<br />
		 * This property is designed to turn-off globally the display of tooltips window.
		 * 
		 * @see ToolTipGuideWindow#show()
		 */
		public static var enabled:Boolean=true;

		/**
		 * Create the standar window guide tooltip and tie to the component movement and behaviour.
		 * 
		 * <h3>Sample Implementation</h3>
		 * <pre>
		 * var ui:ToolTipGuideWindow=ToolTipGuideWindow.show(htmlText, loginForm, true, position);
		 * ui.addEventListener(TextEvent.LINK, handleClick, true, 0, true);
		 * </pre>
		 *
		 * @param text the text to be displayed
		 * @param component the component to tie to
		 * @param autoclose if the close handling interaction is self managed
		 * @param position the desired position
		 * @return an instance of the tool tip ui window
		 */
		public static function show(text:String, component:UIComponent, autoclose:Boolean=true, position:String=ToolTipGuidePosition.RIGHT_OUT):ToolTipGuideWindow
		{
			var gui:ToolTipGuideWindow=new ToolTipGuideWindow();
			gui.arrowPosition=position;
			gui.htmlText=text;
			var resizeHandleFunction:Function=function(on:Event):void
				{
					updatePosition(component, gui, position);
				}
			component.addEventListener(MoveEvent.MOVE, resizeHandleFunction);
			component.addEventListener(ResizeEvent.RESIZE, resizeHandleFunction);
			if (autoclose)
			{
				gui.addEventListener(CloseEvent.CLOSE, removeWindowPanel);
			}
			if (enabled)
			{
				PopUpManager.addPopUp(gui, component);
			}
			updatePosition(component, gui, position);
			return gui;
		}

		/**
		 * Positionning logic
		 * @param component the component to tie to
		 * @param gui the window to move
		 * @param position position kind
		 */
		private static function updatePosition(component:UIComponent, gui:ToolTipGuideWindow, position:String):void
		{
			var padding:Number=5;
			var pt:Point=new Point();
			pt=component.localToGlobal(pt);
			switch (position)
			{
				case ToolTipGuidePosition.LEFT_OUT:
					pt.x=pt.x - gui.width - padding;
					pt.y=pt.y + component.height / 2 - gui.height / 2;
					break;
				case ToolTipGuidePosition.RIGHT_OUT:
					pt.x=component.width + pt.x + padding;
					pt.y=pt.y + component.height / 2 - gui.height / 2;
					break;
				case ToolTipGuidePosition.TOP_OUT:
					pt.x=pt.x + padding;
					pt.y=pt.y - gui.height - padding;
					break;
				case ToolTipGuidePosition.BOTTOM_OUT:
					pt.x=pt.x + padding;
					pt.y=pt.y + component.height + padding;
					break;
			}
			gui.move(pt.x, pt.y);
		}

		private static function removeWindowPanel(event:CloseEvent):void
		{
			var gui:ToolTipGuideWindow=event.currentTarget as ToolTipGuideWindow;
			gui.removeEventListener(CloseEvent.CLOSE, removeWindowPanel);
			PopUpManager.removePopUp(gui);
		}

		/**
		 * @inheritDoc
		 */
		override protected function measure():void
		{
			super.measure();
			measuredMinWidth=240;
			//el ancho
			measuredWidth=measuredMinWidth;
			//el alto
			measuredMinHeight=80;
			measuredHeight=measuredMinHeight;
		}

		/**
		 * @inheritDoc
		 */
		override protected function createChildren():void
		{
			super.createChildren();
			textArea=addChild(new Text()) as Text;
			this.icon=getStyle('icon');

			crossIcon=new UIComponent();
			crossIcon.width=crossIcon.height=6;
			drawCross(crossIcon.graphics);
			addChild(crossIcon);
			crossIcon.addEventListener(MouseEvent.MOUSE_OVER, function(event:MouseEvent):void
				{
					drawCross(crossIcon.graphics, 0x222222);
				});
			crossIcon.addEventListener(MouseEvent.MOUSE_OUT, function(event:MouseEvent):void
				{
					drawCross(crossIcon.graphics);
				});
			crossIcon.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void
				{
					crossIcon.parent.dispatchEvent(new CloseEvent(CloseEvent.CLOSE));
				});
		}

		/**
		 * @inheritDoc
		 */
		override protected function commitProperties():void
		{
			super.commitProperties();
			if (_htmlTextChanged)
			{
				_htmlTextChanged=false;
				textArea.htmlText=_htmlText;
			}
			if (_arrowPositionChanged)
			{
				_arrowPositionChanged=false;
			}
		}

		/**
		 * @inheritDoc
		 */
		override public function styleChanged(styleProp:String):void
		{
			if (styleProp == null)
				return;
			super.styleChanged(styleProp);
			if (styleProp == 'icon')
			{
				this.icon=this.getStyle('icon');
			}
		}

		/**
		 * @inheritDoc
		 */
		override public function set icon(value:Class):void
		{
			super.icon=value;
			if (iconInst != null)
			{
				removeChild(iconInst);
			}
			var newIconClass:Class=value;
			if (newIconClass)
			{
				var iconDispl:DisplayObject=new newIconClass();
				iconInst=new UIComponent();
				iconInst.width=iconDispl.width;
				iconInst.height=iconDispl.height;
				iconInst.addChild(iconDispl);
				addChild(iconInst);
				invalidateSize();
			}
		}

		/**
		 * @inheritDoc
		 */
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			textArea.y=2;
			if (iconInst)
			{
				iconInst.x=2;
				iconInst.y=2;
				textArea.x=iconInst.width + 2;
				textArea.width=unscaledWidth - 12 - iconInst.width;
			}
			else
			{
				textArea.x=0;
				textArea.width=unscaledWidth - 12;
			}
			if (crossIcon)
			{
				crossIcon.y=4;
				crossIcon.x=unscaledWidth - crossIcon.width - 6;
			}
			textArea.height=unscaledHeight - 8;
		}

		/**
		 * Return the String content
		 * @return
		 */
		public function get htmlText():String
		{
			return _htmlText;
		}

		/**
		 * Set the content for display
		 * @param value
		 */
		public function set htmlText(value:String):void
		{
			_htmlText=value;
			_htmlTextChanged=true;
			invalidateProperties();
		}

		/**
		 * Get the current arrow position
		 * @return
		 */
		public function get arrowPosition():String
		{
			return _arrowPosition;
		}

		/**
		 * Set the current arrow position
		 * @return
		 */
		public function set arrowPosition(value:String):void
		{
			if (ToolTipGuidePosition.validPositions.indexOf(value) == -1)
			{
				throw new Error("Invalid toolTip position {" + value + "}.\n" + "Use instead " + ToolTipGuidePosition.validPositions.toString());
			}
			_arrowPosition=value;
			_arrowPositionChanged=true;
			invalidateProperties();
		}

		/**
		 * Draw a cross icon in a simple way!
		 * @param graphics
		 * @param color
		 */
		private static function drawCross(graphics:Graphics, color:int=0xC2C2C2):void
		{
			graphics.clear();
			graphics.beginFill(0xFF3300, 0);
			graphics.moveTo(-2, -2);
			graphics.lineTo(8, -2);
			graphics.lineTo(8, 8);
			graphics.lineTo(-2, 8);
			graphics.lineTo(-2, -2);
			graphics.moveTo(0, 0);

			graphics.lineStyle(2, color);
			graphics.lineTo(6, 6);
			graphics.moveTo(0, 6);
			graphics.lineTo(6, 0);
			graphics.endFill();
		}

	}
}